package com.demo.javaee.data_type;

import cn.lingyangwl.framework.tool.core.ArithmeticUtils;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.text.NumberFormat;

/**
 * BigDecimal常用方法详解
 * {@link BigDecimal#add(BigDecimal)}}: BigDecimal对象中的值相加，返回BigDecimal对象
 * {@link BigDecimal#subtract(BigDecimal)}}: BigDecimal对象中的值相减，返回BigDecimal对象
 * {@link BigDecimal#multiply(BigDecimal)}}: BigDecimal对象中的值相乘，返回BigDecimal对象
 * {@link BigDecimal#divide(BigDecimal)}}: BigDecimal对象中的值相除，返回BigDecimal对象
 * {@link BigDecimal#toString()}}: 将BigDecimal对象中的值转换成字符串
 * {@link BigDecimal#doubleValue()}}: 将BigDecimal对象中的值转换成双精度数
 * {@link BigDecimal#floatValue()}}: 将BigDecimal对象中的值转换成单精度数
 * {@link BigDecimal#longValue()}}: 将BigDecimal对象中的值转换成长整数
 * {@link BigDecimal#intValue()}}: 将BigDecimal对象中的值转换成整数
 * 将BigDecimal对象中的值转换成整数
 *
 * @author shenguangyang
 */
public class BigDecimalTest {
    /**
     * out:
     * a values is:0.1000000000000000055511151231257827021181583404541015625
     * =====================
     * b values is:0.1
     * <p>
     * 原因分析：
     * 1. 参数类型为double的构造方法的结果有一定的不可预知性。有人可能认为在Java中写入new BigDecimal(0.1)
     * 所创建的BigDecimal正好等于 0.1（非标度值 1，其标度为 1），但是它实际上等于
     * 0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法准确地表示为
     * double（或者说对于该情况，不能表示为任何有限长度的二进制小数）。这样，传入到构造方法的值不会正好等于
     * 0.1（虽然表面上等于该值）。
     * <p>
     * 2. String 构造方法是完全可预知的：写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal，它正好等于预期的 0.1。
     * 因此，比较而言， 通常建议优先使用String构造方法。
     * <p>
     * 3. 当double必须用作BigDecimal的源时，请注意，此构造方法提供了一个准确转换；它不提供与以下操作相同的结果：
     * 先使用Double.toString(double)方法，然后使用BigDecimal(String)构造方法，将double转换为String。要获取该结果，
     * 请使用static valueOf(double)方法。
     */
    @Test
    public void t01() {
        BigDecimal a = new BigDecimal(0.1);
        System.out.println("a values is:" + a);
        System.out.println("=====================");
        BigDecimal b = new BigDecimal("0.1");
        System.out.println("b values is:" + b);
    }

    /**
     * 由于NumberFormat类的format()方法可以使用BigDecimal对象作为其参数，可以利用BigDecimal对超出16位
     * 有效数字的货币值，百分值，以及一般数值进行格式化控制。
     * <p>
     * 以利用BigDecimal对货币和百分比格式化为例。首先，创建BigDecimal对象，进行BigDecimal的算术运算后，
     * 分别建立对货币和百分比格式化的引用，最后利用BigDecimal对象作为format()方法的参数，输出其格式化的货币
     * 值和百分比。
     */
    @Test
    public void t02_Format() {
        // 建立货币格式化引用
        NumberFormat currency = NumberFormat.getCurrencyInstance();
        // 建立百分比格式化引用
        NumberFormat percent = NumberFormat.getPercentInstance();
        // 百分比小数点最多3位
        percent.setMaximumFractionDigits(3);

        BigDecimal loanAmount = new BigDecimal("15000.48"); //贷款金额
        BigDecimal interestRate = new BigDecimal("0.008"); //利率
        BigDecimal interest = loanAmount.multiply(interestRate); //相乘

        System.out.println("贷款金额:\t" + currency.format(loanAmount));
        System.out.println("利率:\t" + percent.format(interestRate));
        System.out.println("利息:\t" + currency.format(interest));
    }

    /**
     * BigDecimal格式化保留2为小数，不足则补0
     */
    @Test
    public void t02_FormatTwoToString() {
        System.out.println(ArithmeticUtils.formatToString(new BigDecimal("3.435")));
        System.out.println(ArithmeticUtils.formatToString(new BigDecimal(0)));
        System.out.println(ArithmeticUtils.formatToString(new BigDecimal("0.00")));
        System.out.println(ArithmeticUtils.formatToString(new BigDecimal("0.001")));
        System.out.println(ArithmeticUtils.formatToString(new BigDecimal("0.006")));
        System.out.println(ArithmeticUtils.formatToString(new BigDecimal("0.206")));
    }
}
